home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / SAT 2.3.8 / Demos / SAT Invaders demo ƒ / main.p < prev    next >
Text File  |  1996-05-23  |  11KB  |  352 lines

  1. {================================================}
  2. {=============== SATInvaders main unit ================}
  3. {================================================}
  4.  
  5. { Example file for Ingemars Sprite Animation Toolkit. }
  6. { © Ingemar Ragnemalm 1992 }
  7. { See doc files for legal terms for using this code. }
  8.  
  9. { SATInvaders is a very simple game demonstrating how to use the Sprite Animation}
  10. { Toolkit. It is intended as a minimal demonstration, without many features and options}
  11. { that the other sample program, HeartQuest, has. No high scores or even score, only}
  12. { one life, doesn't save settings, only one kind of enemy, no special effects like explosions}
  13. { etc. However, it is still a full Mac application with menus and event handling (using}
  14. {TransSkel).}
  15.  
  16. {In SAT version 1, this was the "minimal" demo. There are now several even more}
  17. {"minimal" demos, esp. the Tutorial and SATminimal.}
  18.  
  19. program SATInvaders;
  20.  
  21.     uses
  22. {$IFC UNDEFINED THINK_PASCAL}
  23.         Types, QuickDraw, Menus, ToolUtils, Resources, {}
  24.         Events, Windows, Dialogs,
  25. {$ENDC}
  26.         TransSkel, SAT, GameGlobals, SoundConst, StarField, sPlayer, sEnemy, sShot, sMissile;
  27.  
  28.     var
  29.         soundFlag, plotFastFlag, starFieldFlag: Boolean;
  30.  
  31. { -------------------------------------------------------------------- }
  32. {                                Game driver procedures                                }
  33. { -------------------------------------------------------------------- }
  34.  
  35. { Setup a new level. This is called when the game starts and at each new level.}
  36.     procedure SetupLevel (level: integer);
  37.         var
  38.             i, j: integer;
  39.             sp: SpritePtr;
  40.     begin { SetupLevel }
  41.  
  42. { Clear the Sprite list! Note that this leaves the images "dead" on the screen,}
  43. { but we will soon erase them. }
  44.         while gSAT.sRoot <> nil do
  45.             SATKillSprite(gSAT.sRoot);
  46.  
  47.         missileCount := 0; { count variable in mMissile }
  48.  
  49. { Create all the enemy sprites for the level, depending on the level number. }
  50.         for i := 0 to (level + 1) do
  51.             for j := 0 to (level div 2) + 1 do
  52.                 sp := SATNewSprite(-3, i * 40 + 2, j * 40 - 40 * (level div 2 + 1), @SetupEnemy);
  53.  
  54. { Make the player sprite. }
  55.         sp := SATNewSprite(2, gSAT.offSizeH div 2, gSAT.offSizeV - 40, @SetupPlayer);
  56.  
  57. { Copy BackScreen to OffScreen to erase old sprites. }
  58.         CopyBits(gSAT.backScreen.port^.portbits, gSAT.offScreen.port^.portbits, gSAT.offScreen.port^.portrect, gSAT.offScreen.port^.portrect, srcCopy, nil);
  59.         SATRedraw;
  60.     end; { SetupLevel }
  61.  
  62. { Start a new game. Initialize level, score, number of lives, and call setuplevel to make the first level. }
  63.     procedure StartGame;
  64.     begin
  65.         level := 1;
  66.         SetupLevel(level);
  67.     end;
  68.  
  69. { Declare forward since we want to call it from MoveIt }
  70.     procedure DoFileMenu (item: integer);
  71.     forward;
  72.  
  73. { This routine is the game driver. It calls SATRun repeatedly until the game ends or is paused. }
  74. { I also read the keyboard here. This could optionally be moved to the "player object" module. }
  75.  
  76.     procedure MoveIt;
  77.         var
  78.             t: longint;
  79.             theEvent: EventRecord; { för att testa musklick }
  80.     begin
  81.         stillrunning := true; { A flag that tells whether or not to quit this routine. }
  82.  
  83. { Hide cursor and menu bar }
  84.  { NOTE: No matter how we leave the MoveIt procedure, we should ShowCursor. }
  85.         HideCursor;
  86.         SATHideMBar(gSAT.wind.port);
  87.         SATRedraw; {We must redraw the menu bar area. I'm lazy and redraw it all.}
  88.  
  89. { Main loop! Keep running until the game is paused or ends. }
  90.         while stillrunning = true do
  91.             begin
  92.                 t := TickCount; {Remember when we started the last turn through the loop.}
  93.  
  94.                 if starFieldFlag then
  95.                     DoStars;
  96.  
  97. { Here is the real heart of the loop: call Animator once per loop. It will call all the objects,}
  98. { draw and erase them, sort them etc. }
  99.                 SATRun(plotFastFlag);
  100.  
  101. { All the rest of the main loop is game specific, next level, bonus handling, etc. }
  102.  
  103. {Handle the speed of the invaders. Since all move the same way, this is done globally.}
  104.                 if globalspeed.h = 0 then
  105.                     begin
  106.                         downcount := pred(downcount);
  107.                         if downcount <= 0 then
  108.                             begin
  109.                                 globalspeed.h := -lasth;
  110.                                 globalspeed.v := 0;
  111.                                 turnflag := false;
  112.                             end;
  113.                     end
  114.                 else if turnflag then
  115.                     begin
  116.                         downcount := 10;
  117.                         lasth := globalspeed.h;
  118.                         globalspeed.h := 0;
  119.                         globalspeed.v := 3;
  120.                     end;
  121.  
  122. {End of level? If so, set up a new one!}
  123.                 if not gSAT.anyMonsters then
  124.                     begin
  125.                         SATSoundShutUp;
  126.                         level := level + 1;
  127.                         SetupLevel(level);
  128.                     end; {if not anymonsters}
  129.  
  130. { Check for keys being pressed - but don't allow background processing.}
  131. { If you want background processing, either use GetNextEvent+SystemTask or WaitNextEvent (the modern call).}
  132.                 if GetOSEvent(keyDownMask, theEvent) then { keydown only }
  133.                     if BitAnd(theEvent.modifiers, cmdKey) <> 0 then {Command key pressed?}
  134.                         case char(BitAnd(theEvent.message, charCodeMask)) of {With what key?}
  135.                             'q': 
  136.                                 begin {Quit!}
  137.                                     SkelWhoa;        {Tell TransSkel to quit.}
  138. { Do all the things we have to do when we leave MoveIt! }
  139.                                     SATSoundShutUp; { Dispose of sound channel }
  140.                                     FlushEvents(EveryEvent, 0); { To forget events, like mouse clicks etc. }
  141.                                     ShowCursor;
  142.                                     SATShowMBar(gSAT.wind.port);
  143.                                     exit(MoveIt);
  144.                                 end;
  145.                             's': 
  146.                                 begin {Sound on/off}
  147.                                     DoFileMenu(sound);
  148.                                 end;
  149.                             otherwise
  150.                                 ; {Ignore others}
  151.                         end; { case}
  152.  
  153. { Delay, using TickCount so it doesn't matter how fast our Mac is. }
  154.                 while ((TickCount - t) < 3) do {3/60 per frame = 20 fps if possible}
  155.                     ;
  156.             end; { while stillrunning (main loop) }
  157.  
  158.         while not SATSoundDone do
  159.             SATSoundEvents; {Wait for last sound to complete}
  160.  
  161.         ShowCursor; {Balance HideCursor}
  162.         SATShowMBar(gSAT.wind.port);
  163.         FlushEvents(EveryEvent - DiskMask, 0); { To forget events, like mouse clicks etc. except disk events }
  164.  
  165.         SATReportStr('Sorry, game over.');
  166.  
  167.         SATSoundShutUp; { Dispose of sound channel }
  168.     end; { MoveIt }
  169.  
  170.     procedure GameWindUpdate;
  171.         var
  172.             watch: CursHandle;
  173.     begin
  174. {Set the cursor to wait cursor during screen depth change test. If there's no change,}
  175. {the user won't notice.}
  176.         watch := GetCursor(WatchCursor);
  177.         SetCursor(watch^^);
  178.         if SATDepthChangeTest then
  179.             begin
  180. {Do anything needed after a screen depth change. In this demo, nothing.}
  181.             end;
  182.         ReleaseResource(Handle(watch));
  183. {Set the cursor to arrow again.}
  184.         InitCursor;
  185.  
  186. {Process the update event by redrawing the window.}
  187.         SATRedraw;
  188.  
  189. {Note: SATRedraw can be replaced by drawing with CopyBits, i.e.:}
  190. {SATSetPortScreen;}
  191. {CopyBits(offScreen.port^.portBits, gSAT.wind.port^.portBits, offScreen.port^.portRect, offScreen.port^.portRect, srcCopy, nil);}
  192. {plus drawing borders. SATRedraw draws them black.}
  193.     end;
  194.  
  195. {    Process selection from File menu.}
  196.  
  197.     procedure DoFileMenu (item: integer);
  198.     begin
  199.         case item of
  200.             run: 
  201.                 begin
  202. { Test if we have Color QD, and if so, test bit depth! Alert if features^^.PlotFast.}
  203.                     if not ((gSAT.initDepth = 1) or (gSAT.initDepth = 4) or (gSAT.initDepth = 8)) and plotFastFlag then
  204.                         begin
  205.                             SATReportStr('Please uncheck ''Fast animation'' or set the monitor to b/w, 4-bit or 8-bit mode in the Control Panel.');
  206.                             exit(DoFileMenu);
  207.                         end;
  208.                     if SATDepthChangeTest then {Update if necessary}
  209.                         ;
  210.                     StartGame;
  211.                     ShowWindow(gSAT.wind.port);
  212.                     SelectWindow(gSAT.wind.port);
  213.                     GameWindUpdate;
  214.                     MoveIt;
  215.                 end;
  216.             sound: 
  217.                 begin
  218.                     soundFlag := not soundFlag;
  219.                     CheckItem(FileMenu, sound, soundFlag);
  220.                     if soundFlag then { Tell the sound package our settings, so we don't have to bother. }
  221.                         SATSoundOn
  222.                     else
  223.                         SATSoundOff;
  224.                 end;
  225.             fastAnimation: 
  226.                 begin
  227.                     plotFastFlag := not plotFastFlag;
  228.                     CheckItem(fileMenu, fastAnimation, plotFastFlag);
  229.                 end;
  230.             starField: 
  231.                 begin
  232.                     starFieldFlag := not starFieldFlag;
  233.                     CheckItem(fileMenu, starField, starFieldFlag);
  234.                     ToggleStarField(starFieldFlag);
  235.                 end;
  236.             quit: 
  237.                 SkelWhoa;
  238.         end;
  239.     end;
  240.  
  241.     procedure GameWindInit;
  242.     begin
  243. { Tell TransSkel to tell us when to update SATwind. }
  244.         if SkelWindow(gSAT.wind.port, nil, nil, @GameWindUpdate, nil, nil, nil, nil, false) then
  245.             ;
  246.  
  247. {We use SATCustomInit, so we must show the window ourselves}
  248.         ShowWindow(gSAT.wind.port);
  249.         SelectWindow(gSAT.wind.port);
  250. { Draw the contents of the window (to give the user something to look at during the rest of startup). }
  251.         SATRedraw;
  252.     end;
  253.  
  254. { -------------------------------------------------------------------- }
  255. {                        Menu handling procedures                        }
  256. { -------------------------------------------------------------------- }
  257.  
  258. {    Handle selection of "About…" item from Apple menu}
  259.  
  260.     procedure DoAbout;
  261.         var
  262.             versionString: Str255;
  263.     begin
  264.         SATGetVersion(versionString);
  265.         ParamText(versionString, '', '', '');
  266.         if Alert(aboutAlrt, nil) = 1 then
  267.             ;
  268.     end;
  269.  
  270. {    Initialize menus.  Tell TransSkel to process the Apple menu}
  271. {    automatically, and associate the proper procedures with the}
  272. {    File menu.}
  273.  
  274.     procedure SetUpMenus;
  275.     begin
  276.         SkelApple('About SAT Invaders…', @DoAbout);
  277.         fileMenu := GetMenu(fileMenuRes);
  278.         if SkelMenu(fileMenu, @DoFileMenu, nil, true) then
  279.             ;
  280. { Set the following flags so they match the menu }
  281.         soundFlag := true;
  282.         plotFastFlag := true;
  283.     end;
  284.  
  285. { Hide gamewindow on suspend, so the user can get access to disk icons etc. }
  286.  
  287.     procedure DoSuspendResume (b: boolean);
  288.     begin
  289.         if b then
  290.             begin
  291.                 ShowWindow(gSAT.wind.port);
  292.                 SelectWindow(gSAT.wind.port);
  293.             end
  294.         else
  295.             HideWindow(gSAT.wind.port)
  296.     end;
  297.  
  298.     function DoEvt (e: eventRecord): boolean;
  299.     begin
  300.         if e.what = OSevt then
  301.             begin
  302.                 if BAND(BROTL(e.message, 8), $FF) = SuspendResumeMessage then
  303.                     DoSuspendResume(BAnd(e.message, 1) <> 0);
  304.                 DoEvt := true;
  305.             end
  306.         else
  307.             DoEvt := false;
  308.     end; (* end DoEvent *)
  309.  
  310. { -------------------------------------------------------------------- }
  311. {                                    Main                                }
  312. { -------------------------------------------------------------------- }
  313.  
  314.     var
  315.         gameArea: Rect;
  316.  
  317. begin
  318.     SkelInit(6, nil);                { initialize }
  319.  
  320. { Init all the different parts of the game. }
  321.  
  322.     SetUpMenus;                        { install menu handlers }
  323.  
  324.     SetRect(gameArea, 0, 0, 512, 342);
  325. {We use SATCustomInit to cover the full screen INCLUDING menu bar area!}
  326.     SATCustomInit(129, 128, gameArea, nil, nil, true, true, true, true, true);
  327. {SATInit(129, 128, 512, 322);    {PICTs 129 and 128, width 512, height 322.}
  328.     GameWindInit;    { Install the game window (SATwind) in TransSkel and show it. }
  329.     Loadsounds;        { Preload all sound resources }
  330.  
  331. { Call the init routines for all the sprite units (generally to preload faces)!}
  332. { This must be done after SATInit! }
  333.     InitEnemy;
  334.     InitPlayer;
  335.     InitMissile;
  336.     InitShot;
  337.  
  338. {$IFC UNDEFINED THINK_PASCAL}
  339.     qd.randSeed := TickCount;    { Set the randseed to something that is random enough. }
  340. {$ELSEC}
  341.     randSeed := TickCount;    { Set the randseed to something that is random enough. }
  342. {$ENDC}
  343.  
  344.     if 0 < SATSoundInitChannels(2) then
  345.         ; {Use 2 channels}
  346.  
  347.     SkelEventHook(@DoEvt); { Handle MultiFinder-events }
  348.  
  349.     SkelMain;                    { Loop 'til Quit selected }
  350.     SkelClobber;                { Clean up }
  351.     SATSoundShutUp;            { Terminate sounds, free the sound channel. }
  352. end.